var http = require('http');
var https = require('https');
var net = require('net');
var url = require('url');
module.exports = setup;

function setup(server, conf) {
    let p = {
        conf: conf,
        tokens: {}
    }

    function newToken(key, rps) {
        let target = {
            token: rps,
            target: key,
            queue: []
        }
        target.interval = setInterval(function () {
            if (target.token < rps) {
                target.token += 1
            }
        }, 1000 / rps)
        return target
    }
    if (conf.httpTargets) {
        conf.httpTargets.forEach(ele => {
            let token = newToken(ele.target, ele.rps)
            p.tokens[ele.target] = token
        });
    }
    if (conf.sslTargets) {
        conf.sslTargets.forEach(ele => {
            let key = ele.target
            let token = newToken(key, ele.rps)
            p.tokens[key] = token
        });
    }
    if (!server) {
        server = http.createServer()
    }
    server.on('request', onrequest.bind(p))
    server.on('connect', onconnect.bind(p))
    server.on('error', function (e) {
        // console.log(e)
    })
    return server
}

function checkToken(self, key) {
    let i = key.indexOf('?');
    if (i >= 0) {
        key = key.substring(0, i);
    }
    let tokenRec = self.tokens[key]
    if (!tokenRec) {
        return 0
    }
    if (tokenRec.token > 0) {
        tokenRec.token--
        return 1
    } else {
        return 2
    }
}

function onrequest(cReq, cRes) {
    switch (checkToken(this, cReq.url)) {
        case 0:
            cRes.statusCode = 403
            cRes.statusMessage = 'Forbidden By Limit'
            cRes.setHeader('server', 'ReqLimitProxy')
            cRes.end()
            return
        case 1:
            break
        case 2:
            cRes.statusCode = 409
            cRes.statusMessage = 'Conflict By Limit'
            cRes.setHeader('server', 'ReqLimitProxy')
            cRes.end()
            return
    }
    var u = url.parse(cReq.url);
    var protocol = u.protocol;
    var options = {
        hostname: u.hostname,
        port: u.port || protocol=='https:'?443:80,
        path: u.path,
        method: cReq.method,
        headers: cReq.headers
    };
    options.headers['connection'] = 'close';
    var h = protocol=="https:"?https:http;
    var pReq = h.request(options, function (pRes) {
        cRes.writeHead(pRes.statusCode, pRes.headers);
        pRes.pipe(cRes);
    }).on('error', function (e) {
        // cRes.end();
    });

    cReq.pipe(pReq);
}

function onconnect(cReq, cSock) {
    cSock.on('error', function (e) {
        // console.log(e)
    })

    switch (checkToken(this, cReq.url)) {
        case 0:
            cSock.write('HTTP/1.1 403 Forbidden By Limit\r\n\r\n');
            cSock.end()
            return
        case 1:
            break
        case 2:
            cSock.write('HTTP/1.1 409 Conflict By Limit\r\n\r\n');
            cSock.end()
            return
    }
    var u = url.parse('http://' + cReq.url);
    var pSock = net.connect(u.port, u.hostname, function () {
        cSock.write('HTTP/1.1 200 Connection Established\r\n\r\n');
        pSock.pipe(cSock);
    }).on('error', function (e) {
        // cSock.end();
    });

    cSock.pipe(pSock);
}